home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Development Tools & Languages / • Other Platforms / PCCTS 1.31 / Documentation / UPDAT130.txt < prev    next >
Encoding:
Text File  |  1995-03-10  |  21.6 KB  |  682 lines  |  [TEXT/MPS ]

  1.  
  2.                          PCCTS 1.30 Release Notes
  3.  
  4.                     Active Authors for 1.30 Release:
  5.  
  6.                               Terence Parr
  7.                         Parr Research Corporation
  8.                             5517 Pleasant Ave
  9.                           Minneapolis, MN 55419
  10.                               parrt@acm.org
  11.  
  12.                            Russell W. Quong
  13.                    School of Electrical Engineering
  14.                            Purdue University
  15.                         W. Lafayette, IN 47907
  16.                          quong@ecn.purdue.edu
  17.  
  18.                             Other authors:
  19.  
  20.                   Will Cohen, cohenw@ecn.purdue.edu
  21.                   Hank Dietz, hankd@ecn.purdue.edu
  22.  
  23.                            November 1, 1994
  24.  
  25.  
  26.     This document describes the 1.30 release of the Purdue Compiler
  27.     Construction Tool Set (PCCTS).  This file describes the changes
  28.     made to PCCTS 1.23 to arrive at PCCTS 1.30.  A number of major new
  29.     features were added and a few bug fixes were made.  We imagine
  30.     that this will be the last major feature addition to the ANTLR
  31.     description language before a 2.00 version can be built. The
  32.     original 1.00 manual and all release notes are required for a
  33.     complete documentation set for PCCTS.  A book is in the works and
  34.     the papers provided at the ftp site don't hurt.
  35.  
  36.     PCCTS is in the public-domain and can be obtained at
  37.     everest.ee.umn.edu in pub/pccts/1.30.  The newsgroup
  38.     comp.compilers.tools.pccts provides a discussion forum.  To
  39.     receive future release broadcast messages, register yourself by
  40.     sending email to pccts@ecn.purdue.edu with a ``Subject:'' line of
  41.     ``register''.
  42.  
  43.     The authors make no claims that this software will do what you
  44.     want, that this manual is any good, or that the software actually
  45.     works---use PCCTS at your own risk.  Bug reports and/or cheery
  46.     reports of its usefulness are very welcome, however.
  47.  
  48.     The maintenance and support of all PCCTS tools is primarily
  49.     provided by Parr Research Corporation, Minneapolis MN.  Please see
  50.     file PCCTS.FUTURE for more information.  All PCCTS tools currently
  51.     in the public domain will continue to be in the public domain.
  52.  
  53.  
  54. I. NEW FEATURES
  55.  
  56. The only new features are element labels and parser exception
  57. handling, but they significantly increase the capabilities of ANTLR.
  58. The programmer now has complete control over how errors (semantic and
  59. syntactic) are handled.  Further, the element labels are generally
  60. useful and should be considered the preferred method for accessing
  61. lexical information about tokens.  [Please note that parser exception
  62. handling is to be considered in alpha-release state].
  63.  
  64. A. ELEMENT LABELING
  65.  
  66. Actions in an ANTLR grammar may access attributes via labels of the
  67. form ``$label'' attached to token and rule references rather than the
  68. conventional ``$i'' for some integer i.  By using symbols instead of
  69. integer identifiers, grammars are more readable and action parameters
  70. are not sensitive to changes in rule element positions.
  71.  
  72. The form of a label is:
  73.  
  74. label:element
  75.  
  76. where element is either a token reference or a rule reference.  To
  77. refer to the attribute (C interface) or token pointer (C++ interface)
  78. of that element in an action, use
  79.  
  80. $label
  81.  
  82. within an action or rule argument list.  For example,
  83.  
  84. a : t:ID <<printf("%s\n", $t->getText());>>
  85.   ;
  86.  
  87. [using the C++ interface].  To reference the tree variable associated
  88. with element, use
  89.  
  90. #label
  91.  
  92. When using parser exception handling, simply reference ``label'' to
  93. attach a handler to a particular rule reference.  For example,
  94.  
  95. a : t:b
  96.     exception[t]
  97.         default : <<trap any error found during call to 'b'>>
  98.   ;
  99.  
  100. Labels must be unique per rule as they have rule scope.  Labels may be
  101. accessed from parser exception handlers.
  102.  
  103. B. PARSER EXCEPTION HANDLING 
  104.  
  105. ***** CONSIDERED ALPHA QUALITY STUFF *****
  106.  
  107. ANTLR has two mechanisms for error reporting and recovery.  In the
  108. first mechanism, ANTLR automatically generates error messages using a
  109. simple, effective heuristic that is sufficient for many applications.
  110. However, when more sophisticated error handling is required, say for
  111. commercial-quality software, ANTLR now supports a second mechanism
  112. called ``parser exception handling'' that provides the flexibility of
  113. hand-built reporting and recovery in a convenient framework.  Parser
  114. exception handling has much in common with C++ exception handling; we
  115. do not actually use C++ exceptions in our implementation and, hence,
  116. parser exception handling can be used with either the ANTLR C or C++
  117. interface.
  118.  
  119. Parser exception handling provides a unified framework for reporting
  120. and recovering from semantic and syntactic errors; note that automatic
  121. mechanisms typically do not consider semantic errors.  Parser
  122. exception handling provides nearly the flexibility of a hand-built
  123. parser [We have not played with the semantic recovery yet, but will
  124. soon--you cannot define your own error signals at this point].
  125.  
  126. We illustrate the use of parser exception handlers by demonstrating
  127. how they are used to generate a better error message than the
  128. automatic mechanism, which simply reports where the error was detected
  129. and what was expected.  Consider matching the rule stat using the
  130. following grammar fragment,
  131.  
  132. stat:   "if" expr "then" stat { "else" stat }
  133.     |   "while" expr "do" stat
  134.     |   VAR ":=" expr ";"
  135.     |   "begin" ( stat )+ "end"
  136.     ;
  137.  
  138. expr:   atom ( "\+" atom )*
  139.     ;
  140.  
  141. atom:   INT
  142.     |   FLOAT
  143.     ;
  144.  
  145. where INT, FLOAT, and VAR are defined as integer, float and identifier
  146. tokens.  Upon input
  147.  
  148. if 34+ then i:=1;
  149.  
  150. the automatic error mechanism would report
  151.  
  152. line 1: syntax error at "then" missing { INT FLOAT }.
  153.  
  154. However, because we know the context in which the expr production was
  155. attempted, an improved error message could be generated; i.e., it
  156. could indicate the expression was both in an if-statement and that it
  157. was a conditional--as opposed to the right-hand-side of an assignment
  158. statement, for example.  A better message would be
  159.  
  160. line 1: if-statement: malformed conditional at "then"
  161.  
  162. One way to achieve this error message is to modify the original stat
  163. grammar as follows
  164.  
  165. stat:   "if" e:expr "then" stat { "else" stat }
  166.         exception[e]
  167.           catch MismatchedToken :
  168.           catch NoViableAlt :
  169.              <<
  170.              fprintf(stderr,
  171.                      "line %d: if-statement: malformed conditional at \"%s\"\n",
  172.                      zzline, LATEXT(1));
  173.              zzconsumeUntilToken(THEN);
  174.              >>
  175.     |   "while" expr "do" stat
  176.    ...
  177.     ;
  178. }
  179.  
  180. where THEN is the token type associated with "then"; MismatchedToken
  181. and NoViableAlt are predefined error signals.  The notation ``e:expr''
  182. attaches the label e to the expr rule reference.  Labels allow the
  183. exception handler to catch errors encountered specifically for input
  184. matched during that reference.
  185.  
  186. Good error handling requires programmer intervention.  Automatic
  187. mechanisms typically do not perform well, because they cannot easily
  188. analyze the state of the parser (e.g., the symbol stack of a
  189. table-driven parser or the program counter of a recursive-descent
  190. parser).  Knowing where to report errors and how to recover from them
  191. must be done with a programmer's experience.  While more programming
  192. effort is required than for automatic mechanisms, ANTLR's parser
  193. exception handling provides a convenient, sophisticated mechanism that
  194. rivals the flexibility of hand-coded schemes.
  195.  
  196. ANTLR defaults to using the old, automatic mechanism.  Any use of the
  197. keyword "exception" triggers the new mechanism.
  198.  
  199. We now provide specific ANTLR programming details for parser exception
  200. handling.
  201.  
  202.                             Syntax
  203.  
  204. A group of exception handlers may be specified after any alternative,
  205. after the ";" of a rule definition, and default/global exceptions may
  206. be specified before the list of rules.  The syntax for an exception
  207. group is as follows:
  208.  
  209. exception_group
  210.     : "exception" { Label_in_brackets }
  211.           ( exception_handler )*
  212.       { "default" ":" Action }
  213.     ;
  214.  
  215. exception_handler
  216.     : "catch" SIGNAL ":" { Action }
  217.     ;
  218.  
  219. where SIGNAL is one of:
  220.  
  221.     NoViableAlt     -- None of the alternatives were predicted
  222.     NoSemViableAlt  -- See below
  223.     MismatchedToken -- Didn't find the token we were looking for
  224.  
  225. You can also use a "default :" clause, which matches any signal, in
  226. your exception group.
  227.  
  228. Currently, you cannot define your own signals.
  229.  
  230. You can define multiple signals for a single action.  E.g.,
  231.  
  232.     exception
  233.         catch MismatchedToken   :
  234.         catch NoViableAlt       :
  235.         catch NoSemViableAlt    :
  236.             <<
  237.             printf("stat:caught predefined signal\n");
  238.             consumeUntil(DIE_set);
  239.             >>
  240.  
  241. If a label (attached to a rule reference) is specified for an
  242. exception group, that group may be specified after the end of the ";"
  243. rule terminator.  ANTLR can still uniquely identify which rule
  244. reference to associate the group with; it often makes a rule cleaner
  245. to have most of the exception handlers at the end of the rule.  For
  246. example,
  247.  
  248. a : A t:expr B
  249.   | ...
  250.   ;
  251.   exception[t]
  252.     catch ...
  253.     catch ...
  254.  
  255. The NoViableAlt signal only makes sense for exception groups with
  256. labels and for rule exception groups.
  257.  
  258.  
  259.               Exception Handler Order of Execution
  260.  
  261. Given a signal, S, the handler that is invoked is determined by
  262. looking through the list of enabled handlers in a specific order.
  263.  
  264. Loosely speaking, we say that a handler is "enabled" (becomes active)
  265. and pushed on an exception stack when it has been seen by the parser
  266. on its way down the parse tree.  A handler is "disabled" and taken off
  267. the exception stack when the associated grammar fragment is
  268. successfully parsed.  The formal rules for enabling are:
  269.  
  270. o    All global/default handlers are enabled upon parser entry.
  271.  
  272. o    Exception handlers specified after an alternative become enabled
  273.     when that alternative is predicted.
  274.  
  275. o    Exception handlers specified for a rule become enabled when the
  276.     rule is invoked.
  277.  
  278. o    Exception handlers tied to a particular rule reference within
  279.     an alternative are enabled just before the invocation of that
  280.     rule reference.
  281.  
  282. Disabling rules are:
  283.  
  284. o    All global/default handlers are disabled upon parser exit.
  285.  
  286. o    Exception handlers specified after an alternative are disabled
  287.     when that alternative has been parsed completely (successfully).
  288.  
  289. o    Exception handlers specified for a rule become disabled just
  290.     before the rule returns.
  291.  
  292. o    Exception handlers tied to a particular rule reference within
  293.     an alternative are disabled just after the return from that
  294.     rule reference.
  295.  
  296. Upon an error condition, the parser with throw an exception signal, S;
  297. [in the future, the user will be able to throw user-defined
  298. exceptions].  Starting at the top of the stack, each exception group
  299. is examined looking for a handler for S.  The first S handler found on
  300. the stack is executed.  In practice, the run time stack and hardware
  301. program counter are used to search for the appropriated handler.  This
  302. amounts to the following:
  303.  
  304. o    If there is an exception specified for the enclosing alternative,
  305.     then look for S in that group first.
  306.  
  307. o    If there is no exception for that alternative or that group did not
  308.     specify an S handler, then look for S in the enclosing rule's
  309.     exception group.
  310.  
  311. o    Global/default handlers are like macros that are inserted into
  312.     the rule exception group for each rule.
  313.  
  314. o    If there is no rule exception or that group did not specify
  315.     an S handler, then return from the enclosing rule with the current
  316.     error signal still set to S.
  317.  
  318. o    If there is an exception group attached (via label) to the rule
  319.     that just returned, check that exception group for S.
  320.  
  321. o    If an exception group attached to a rule reference does not have
  322.     an S handler, then look for S in the enclosing rule's exception
  323.     group.
  324.  
  325. This process continues until an S handler is found or a return
  326. instruction is executed in starting rule.
  327.  
  328. These guidelines are best described with an example:
  329.  
  330. a   :   A c B
  331.         exception                                   /* 1 */
  332.             catch MismatchedToken : <<ACTION1>>
  333.     |   C t:d D
  334.         exception                                   /* 2 */
  335.             catch MismatchedToken : <<ACTION2>>
  336.             catch NoViableAlt : <<ACTION3>>
  337.     ;
  338.     exception[t]                                    /* 3 */
  339.         catch NoViableAlt : <<ACTION4>>
  340.     exception                                       /* 4 */
  341.         catch NoViableAlt : <<ACTION5>>
  342.  
  343. c   :   E
  344.     ;
  345.  
  346. d   :   e
  347.     ;
  348.  
  349. e   :   F
  350.     |   G
  351.     ;
  352.     exception                                       /* 5 */
  353.         catch MismatchedToken : <<ACTION6>>
  354.  
  355. The following table summarizes the sequence in which the exception
  356. groups are tested:
  357.  
  358. INPUT       EXCEPTION GROUP TESTING SEQUENCE        ACTION EXECUTED
  359. D E B       4                                       ACTION5
  360. A E D       1                                       ACTION1
  361. A F B       1                                       ACTION6
  362. A F B       1                                       ACTION6
  363. C F B       2                                       ACTION2
  364. C E D       5,2                                     ACTION3
  365.  
  366. The global/default handlers are like macro insertions.  For example:
  367.  
  368. exception
  369.     catch NoViableAlt : <<blah blah>>
  370.  
  371. a : A
  372.   ;
  373.   exception
  374.       catch MismatchedToken : <<ack;>>
  375.  
  376. b : B
  377.   ;
  378.  
  379. This is functionally equivalent to:
  380.  
  381. a : A
  382.   ;
  383.   exception
  384.       catch MismatchedToken : <<ack;>>
  385.       catch NoViableAlt : <<blah blah>>
  386.  
  387. b : B
  388.   ;
  389.   exception
  390.       catch NoViableAlt : <<blah blah>>
  391.  
  392. [You will soon be able to throw the same or a different signal from an
  393. exception handler.  This makes sense when you want a "panic" signal to
  394. propagate back up the parse tree so that all rules can clean up.]
  395.  
  396.  
  397.                 Modifications to Code Generation
  398.  
  399. The following generic changes were made to facilitate exception
  400. handling:
  401.  
  402. o    Each rule reference now has a signal parameter which returns 0 if no
  403.     error occurred during that reference or it returns a nonzero signal S.
  404.  
  405. o    The MATCH() macro has been modified to signal Mismatched token
  406.     rather than calling zzsyn().
  407.  
  408. o    When no viable alternative is found, NoViableAlt is signaled
  409.     rather than calling the zzsyn() routine.
  410.  
  411. o    The parser no longer resynchronizes automatically.  See below.
  412.  
  413.  
  414.              Semantic Predicates and NoSemViableAlt
  415.  
  416. When the input stream does not predict any of the alternatives in the
  417. current list of possible alternatives, NoViableAlt is signaled.
  418. However, what happens when semantic predicates are specified in that
  419. alternative list?  It turns out that the following simple strategy
  420. handles this case:
  421.  
  422. ``If NoViableAlt is signaled and at least one semantic predicate (for
  423. a syntactically viable alternative) failed, signal NoSemViableAlt
  424. instead of NoViableAlt.''
  425.  
  426. It would be very misleading to just throw NoViableAlt when in fact one
  427. or more alternatives were syntactically viable; i.e., the reason that
  428. no alternative was predicted was due to a semantic invalidity--a
  429. different signal must be thrown.  For example,
  430.  
  431. expr : <<P1>>? ID ...  /* function call */
  432.      | <<P2>>? ID ...  /* array reference */
  433.      | INT
  434.      ;
  435.   exception
  436.     catch NoViableAlt :    <<no ID or INT was found>>
  437.     catch NoSemViableAlt : <<an ID was found, but it was not valid>>
  438.  
  439. Typically, the programmer would want to give very different error
  440. messages for the two different situations.  Specifically, giving a
  441. message such as "syntax error at ID missing { ID INT }" would be very
  442. misleading (i.e., wrong).
  443.  
  444. In future versions, we may enhance this to throw a different signal
  445. depending on which predicate failed.
  446.  
  447. Semantic predicates that are not used to predict alternatives do not
  448. yet throw signals.  You must continue to use the fail-action for that
  449. predicate.
  450.  
  451.  
  452.                    Resynchronizing the Parser
  453.  
  454. When an error occurs while parsing rule R, the parser will generally
  455. not be able to continue parsing anywhere within that rule--it will
  456. return immediately after executing any exception code.  The one
  457. exception is for exceptions with labels.  In this case, the parser
  458. knows exactly where in the alternative you would like to continue
  459. parsing from.
  460.  
  461. To allow manual resynchronization of the parser, you may use two new
  462. functions:
  463.  
  464. zzconsumeUntil(X_set)
  465.     Consume tokens until you see a token in the token class X.  ANTLR
  466.     now generates a packed bitset called X_set for each token class X.
  467.  
  468. zzconsumeUntilToken(T)
  469.     Consume tokens until you see token T.
  470.  
  471. For example,
  472.  
  473. #tokclass RESYNCH { A C }
  474.  
  475. a : b A
  476.   | b C
  477.   ;
  478.  
  479. b : B
  480.     exception
  481.         catch MismatchedToken : // consume until FOLLOW(b)
  482.             <<print error message; zzconsumeUntil(RESYNCH_set);>>
  483.   ;
  484.  
  485. Soon, you will be able to reference the FOLLOW(R) and FIRST(R) for a
  486. rule R to make resynchronization set construction easier.
  487.  
  488. You may also use zzset_el() to test for membership in a token class.
  489.  
  490. int zzset_el(unsigned b, SetWordType *p)
  491.  
  492. For example,
  493.  
  494. <<if ( zzset_el(LA(1), X_set) ) blah blah blah;>>
  495.  
  496. In C++ mode, simply remove the "zz" prefix from the function names.
  497.  
  498.  
  499.                            Example
  500.  
  501. The following grammar demonstrates the use of parser exception
  502. handling using the C interface (testcpp/13/test.g provides a C++
  503. example).  Given input:
  504.  
  505.     if a+ then a=b+b;
  506.  
  507. the output should be:
  508.  
  509.     invalid conditional in 'if' statement
  510.     found assignment to a
  511.  
  512. ----------------------------------------------------------------
  513. #header <<#include "charbuf.h">>
  514.  
  515. <<
  516. main()
  517. {
  518.     ANTLR(rule(), stdin);
  519. }
  520. >>
  521.  
  522. #token "[\ \t]+"    <<zzskip();>>
  523. #token "\n"            <<zzskip(); zzline++;>>
  524. #token THEN    "then"
  525. #tokclass DIE { "@" "if" ID "else" }
  526.  
  527. rule:    ( stat )+
  528.     ;
  529.  
  530. stat:    "if" t:expr "then" stat { "else" stat }
  531.     |    u:ID "=" expr ";"
  532.         <<printf("found assignment to %s\n", $u.text);>>
  533.     ;
  534.       exception[t]
  535.         default    :
  536.             <<
  537.             printf("invalid conditional in 'if' statement\n");
  538.             zzconsumeUntilToken(THEN);
  539.             >>
  540.       exception
  541.         catch MismatchedToken    :
  542.         catch NoViableAlt        :
  543.         catch NoSemViableAlt    :
  544.             <<
  545.             printf("stat:caught predefined signal\n");
  546.             zzconsumeUntil(DIE_set);
  547.             >>
  548.  
  549. expr:    expr1 ("\+" expr1)*
  550.     ;
  551.  
  552. expr1
  553.     :    expr2 ("\*" expr2)*
  554.     ;
  555.  
  556. expr2:    ID
  557.     ;
  558.  
  559. #token ID "[a-z]+"
  560. ----------------------------------------------------------------
  561.  
  562. C. LEXCLASS SAVE/RESTORE
  563.  
  564. [In the words of Ken Weinert:]
  565.  
  566. This section describes the addition of the mode stack operations
  567. defined in Tom Moog's NOTES.newbie document. By defining a variable
  568. USER_ZZMODE_STACK at compile time, you can include these functions for
  569. use in your grammars.
  570.  
  571. By default, the #define ZZSTACK_MAX_MODE is set to 32 which gives a
  572. mode stack of depth 64. If this is too shallow, defining
  573. ZZSTACK_MAX_MODE to a different value in the makefile will override
  574. the default.
  575.  
  576. Four functions are defined with this modification: zzmpush(),
  577. zzmpop(), zzsave_mode_stack(), and zzrestore_mode_stack().
  578.  
  579. zzmpush(int newMode)
  580.     push the current mode on the stack and make newMode the current mode.
  581.  
  582. zzmpop()
  583.     make current the previous mode
  584.  
  585. zzsave_mode_stack(int modeStack[], int *modeLevel)
  586.     save the current mode stack and depth into indicated variables.
  587.     Analogous to zzsave_[antlr|dlg]_state().
  588.  
  589. zzrestore_mode_stack(int modeStack[], int *modeLevel)
  590.     restore the mode stack and depth from indicated variables.
  591.     Analogous to zzrestore_[antlr|dlg]_state().
  592.  
  593. II. CHANGES AND BUG FIXES
  594.  
  595. o    Tokens may now be labeled rather than using the $i interface.  The
  596.     two are mutually exclusive in the sense that using $i prevents usage
  597.     of $label.
  598.  
  599. o    Added parser exception handling.
  600.  
  601. o    Added #ifdef gate to tokens.h and class definition file for C/C++
  602.     mode.
  603.  
  604. o    Made the #tokdefs file reader ignore gates on the head of files.
  605.  
  606. o    You can no longer pass init-actions to blocks like this (A|B)[action].
  607.  
  608. o    There was a bug in the code generation for (...)* loops for k>1.
  609.     It used a linear approximate lookahead decision instead of full LL(k).
  610.     It also used the wrong prediction expression for exiting the loop.
  611.  
  612. o    Token class X now results in C/C++ bitset X_set rather than zzerr%d.
  613.  
  614. o    ANTLR now allows "@" in a token class.
  615.  
  616. o    Added consumeUntil and consumeUntilToken functions for resynching
  617.     parser in exception handlers.
  618.  
  619. o    Added testcpp/13 to test exception handling.
  620.  
  621. o    A warning is now generated if you reference a non-token element
  622.     with $i for some integer i in C++ mode.
  623.  
  624. o    There was a bug in the code generation for (...)+ loops.  It
  625.     did not put predicates into "do while"--just at front if-gate.
  626.     E.g.,
  627.  
  628.     a : ( b )+ ;
  629.     b : <<pred>>? A;
  630.  
  631.     did not work.
  632.  
  633. o    For 16 bit machines, the ANTLRTokenBuffer file was using some
  634.     implementation-dependent pointer manipulation.  This has been
  635.     changed.
  636.  
  637. o    Semantic predicates and -gl option did not work because ANTLR
  638.     tried to insert line information at the end of a line rather 
  639.     that at the beginning where the C/C++ compiler wants it.
  640.  
  641. o    Added "const" to the arguments of the zzerr pointer and zzerrstd().
  642.     If you have defined a dlg error routine, you must change the definition
  643.     accordingly.
  644.  
  645.  
  646. III. A FEW KNOWN BUGS
  647.  
  648. o    I would like to make an auto test script for the C++ samples to
  649.     check their input/output.
  650.  
  651. o    I haven't figured out how to handle deallocation of token objects
  652.     created.  Sometimes the programmer has allocated them in a totally
  653.     different application and doesn't want ANTLR to track and delete
  654.     them.
  655.  
  656. o    FOLLOW(rule) and FIRST(rule) capabilities need to be added to the
  657.     tokclass declaration.
  658.  
  659. o    No warning is given for nonstandard signals used in parser exception
  660.     handling.
  661.  
  662. o    No warning is given if $label is not defined.
  663.  
  664. o    Nothing has been done about the failure of semantic predicates
  665.     with regards to exception handling.
  666.  
  667. o    The demand lookahead in C++ mode is still wacked.
  668.  
  669. o    Can't do multiple return values in C++ still.
  670.  
  671. o    No warning is given if all alts of a block are guesses: (...)?.
  672.  
  673.  
  674. IV. ACKNOWLEDGEMENTS
  675.  
  676. Thanks to all you folks who tested 1.30 before its release.  Thanks to
  677. the folks at the First Annual PCCTS workshop (held at NeXT July 1994)
  678. who helped refine the syntax for the parser exception handling.
  679.  
  680. Thanks goes to the folks at NeXT for prodding us about good error
  681. recovery.
  682.